// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include <cinttypes>
#include <compare>
#include <cstring>

#include <zencore/memory.h>

namespace zen {

class CompositeBuffer;
class IoBuffer;
class StringBuilderBase;

/**
 * BLAKE3 hash - 256 bits
 */
struct BLAKE3
{
	uint8_t Hash[32];

	inline auto operator<=>(const BLAKE3& Rhs) const = default;

	static BLAKE3	   HashBuffer(const CompositeBuffer& Buffer);
	static BLAKE3	   HashBuffer(const IoBuffer& Buffer);
	static BLAKE3	   HashMemory(const void* Data, size_t ByteCount);
	static BLAKE3	   FromHexString(const char* String);
	const char*		   ToHexString(char* OutString /* 40 characters + NUL terminator */) const;
	StringBuilderBase& ToHexString(StringBuilderBase& OutBuilder) const;

	static const int StringLength = 64;
	typedef char	 String_t[StringLength + 1];

	static BLAKE3 Zero;	 // Initialized to all zeroes

	struct Hasher
	{
		size_t operator()(const BLAKE3& v) const
		{
			size_t h;
			memcpy(&h, v.Hash, sizeof h);
			return h;
		}
	};
};

struct BLAKE3Stream
{
	BLAKE3Stream();

	void		  Reset();									   // Begin streaming hash compute (not needed on freshly constructed instance)
	BLAKE3Stream& Append(const void* data, size_t byteCount);  // Append another chunk
	BLAKE3Stream& Append(MemoryView DataView) { return Append(DataView.GetData(), DataView.GetSize()); }  // Append another chunk
	BLAKE3		  GetHash();  // Obtain final hash. If you wish to reuse the instance call reset()

private:
	alignas(16) uint8_t m_HashState[2048];
};

void blake3_forcelink();  // internal

}  // namespace zen
